﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace MuggleTactics
{
    class Battle
    {
        public bool isTurn;
        private bool moved;
        public enum ActionInput
        {
            Move,
            Spell,
            Item
        }
        // ? allows actionInput to be nullable
        private ActionInput? actionInput;

        private int selectedTileIndex = -1;

        private int usableInput = -1;
        public List<int> tilesInRange;
        public List<Unit> units;
        public List<Tile> tiles;
        private int activeUnitIndex = -1;
        private Unit activeUnit;

        #region setters
        public void setActionInput(ActionInput actionInput)
        {
            this.actionInput = actionInput;
        }

        public void setUsableInput(int spellInput)
        {
            this.usableInput = spellInput;
        }
        #endregion

        #region getters
        public Unit getActiveUnit() { return this.activeUnit; }
        #endregion


        public Battle(List<Unit> units, List<Tile> tiles)
        {
            this.units = units;
            this.tiles = tiles;
        }

        public void update()
        {
            turn();
        }

        private void action()
        {

            if (actionInput != null)
            {
                switch (actionInput)
                {
                    case ActionInput.Move:
                        if (!moved)
                        {
                            doMove();

                        }

                        break;
                    case ActionInput.Spell:
                        Game1.setSelectionState(Game1.SelectionState.spellSelection);
                        doUseable();
                        break;
                    case ActionInput.Item:
                        Game1.setSelectionState(Game1.SelectionState.itemSelection);
                        doUseable();
                        break;
                    default:
                        break;
                }
            }

            selectedTileIndex = -1;
        }

        private void doMove()
        {
            //Console.WriteLine(" am moving"); // Prints out value to console 
            getTilesInRange(170, activeUnit.getPosition);

            Game1.setSelectionState(Game1.getTileSelectionState());


            //while (selectedTileIndex == -1) { }


            if (selectedTileIndex > -1 && tilesInRange.Contains(selectedTileIndex))
            {
                Vector2 tmp = activeUnit.getPosition;
                Vector2 oldPosition = activeUnit.getPosition;

                tmp.X -= 10;
                int oldTileIndex = findTileWithLocation(tmp);                
                tiles[oldTileIndex].setPiece(null);                
                tiles[selectedTileIndex].setPiece(activeUnit);

                activeUnit.setPosition(tiles[selectedTileIndex].getLocation());
                moved = true;
                Game1.selectionState = Game1.SelectionState.actionSelection;

                    if (oldPosition.X > activeUnit.getPosition.X && oldPosition.Y < activeUnit.getPosition.Y)
                    {
                        activeUnit.setCurrentFrame(new Point(0, 1));
                    }
                    else if (oldPosition.X < activeUnit.getPosition.X)
                    {
                        activeUnit.setCurrentFrame(new Point(0, 2));
                    }
                    if (oldPosition.Y < activeUnit.getPosition.Y && oldPosition.X > activeUnit.getPosition.X)
                    {
                        activeUnit.setCurrentFrame(new Point(0, 0));
                    }
                    else if (oldPosition.Y > activeUnit.getPosition.Y)
                    {
                        activeUnit.setCurrentFrame(new Point(0, 3));
                    }
                action();
            }
        }

        private void doUseable()
        {
            Usable usable = null;

            if (usableInput > 0)
            {
                if (!isEnemyInRange(activeUnit.getSingleSpell(usableInput).getRange(), activeUnit.getPosition))
                {
                    isTurn = false;
                    return;
                }
              // getTilesInRange(activeUnit.getSingleSpell(usableInput).getRange(), activeUnit.getPosition);
                Game1.setSelectionState(Game1.getTileSelectionState());
            }

            if (selectedTileIndex >= 0)
            {
                switch (actionInput)
                {
                    case ActionInput.Spell:
                        Game1.setSelectionState(Game1.getSpellSelectionState());
                        usable = activeUnit.getSingleSpell(usableInput);
                        Spell spell = (Spell)usable;
                        // decrease MP
                        activeUnit.modifyStat(spell.getStat(), spell.getValue());
                        break;
                    case ActionInput.Item:
                        Game1.setSelectionState(Game1.getItemSelectionState());
                        usable = activeUnit.getSingleItem(usableInput);
                        Item item = (Item)usable;
                        // TODO: decrease item count                    
                        break;

                }

                // use usable
                Unit unit = (Unit)tiles.ElementAt(selectedTileIndex).getPiece();
                unit.modifyStat(usable.getStat(), usable.getValue());
                isTurn = false;
                //moved = false;
                //Game1.setSelectionState(Game1.SelectionState.actionSelection);

            }
        }

        private int findTileWithLocation(Vector2 v)
        {
            foreach (Tile t in tiles)
            {
                if (t.getLocation() == v)
                {
                    return tiles.IndexOf(t);
                }

            }
            return -1;
        }

        public void tileSelectionInRange(int index)
        {
            while (actionInput == null) { }

            switch (actionInput)
            {
                case ActionInput.Move:
                    if (!tiles[index].getIsOccupied())
                    {

                        selectedTileIndex = index;
                    }
                    break;
                case ActionInput.Spell:
                case ActionInput.Item:
                    //if (tiles[index].getPiece().GetType() == typeof(Unit))
                    // {
                    if (tiles[index].getPiece() is Unit)
                    {
                        selectedTileIndex = index;
                    }
                    //}

                    break;

                default:
                    break;

            }
        }

        public void getTilesInRange(int range, Vector2 position)
        {

            tilesInRange = new List<int>();
            foreach (Tile t in tiles)
            {

                int distance = (int)Math.Floor(Vector2.Distance(t.getLocation(), position));
                if (distance <= range)
                {
                    t.setInRange(true);

                    tilesInRange.Add(tiles.IndexOf(t));


                }
            }

        }

        public void getTilesInRange(int range, Vector2 position, bool straight)
        {
            tilesInRange = new List<int>();
            for(int i = 0; i < range;i++){

               tilesInRange.Add(findTileWithLocation(new Vector2(position.X + 1,position.Y + 1)));
            }       

        }

        private void nextUnit()
        {
            if (activeUnitIndex >= units.Count - 1)
            {
                activeUnitIndex = -1;
            }
            activeUnitIndex++;
            Console.WriteLine(activeUnitIndex);
            activeUnit = units[activeUnitIndex];
            moved = false;
            actionInput = null;
            Game1.selectionState = Game1.SelectionState.actionSelection;
            isTurn = true;
        }

        private void turn()
        {
            if (!isTurn)
            {
                nextUnit();
            }

            if (activeUnit.getHitPoints() > 0)
            {
                if (activeUnit.getIsPlayer())
                {
                    //Console.WriteLine("Is player player()");
                    playerTurn();
                }
                else
                {
                    Console.WriteLine("enemycall");
                    enemyTurn();
                }

            }
            else
            {
                isTurn = false;
            }
            
        }

        private void playerTurn()
        {
            //Game1.setSelectionState(Game1.getActionSelectionState()); //for tesing
            //Game1.setSelectionState(Game1.getTileSelectionState()); //for testing
            if (actionInput != null)
            {


                if (tilesInRange != null)
                {
                    clearTilesInRange();
                }
                action();
            }
        }

        private void enemyTurn()
        {
            int r = 80;
            Unit target = isPlayerInRange(r, activeUnit.getPosition);
            if (target != null)
            {
                Spell curSpell;
                if (activeUnit.getMagicPoints() > 10)
                {
                    curSpell = activeUnit.getSingleSpell(1);
                }
                else
                {
                    curSpell = activeUnit.getSingleSpell(3);
                }
                target.modifyStat(StatsHelper.Stat.hitPoints, curSpell.getValue());
                activeUnit.modifyStat(StatsHelper.Stat.magicPoints, curSpell.getValue());
            }
            else
            {
                // heal if hp low
                if (activeUnit.getHitPoints() < (activeUnit.getHitPoints() / 3))
                {
                    // Active unit supposedly has items, use heal item here
                }
                else
                {
                    // else move
                    getTilesInRange(r, activeUnit.getPosition);

                    Random random = new Random();
                    int randomNumber = random.Next(0, tilesInRange.Count);

                    activeUnit.setPosition(tiles[randomNumber].getLocation());
                }
            }
            
            isTurn = false;
        }

        private Unit isPlayerInRange(int range, Vector2 position)
        {
            getTilesInRange(range, position);
            foreach (int i in tilesInRange)
            {

                if (tiles[i].getPiece() is Unit)
                {
                    Unit tmpUnit = (Unit)tiles[i].getPiece();
                    if (tmpUnit.getIsPlayer()) { return tmpUnit; }
                }
            }
            return null;
        }
        


        private bool isEnemyInRange(int range, Vector2 position)
        {
            getTilesInRange(range, position);
            foreach (int i in tilesInRange)
            {

                if (tiles[i].getPiece() is Unit)
                {
                    Unit tmpUnit = (Unit)tiles[i].getPiece();
                    if (!tmpUnit.getIsPlayer()) { return true; }
                }
            }
            return false;
        }


        public List<String> getSpellNames()
        {
            return activeUnit.getSpellNames();
        }

        private void clearTilesInRange()
        {
            foreach (int tile in tilesInRange)
            {
                tiles[tile].setInRange(false);
            }
            tilesInRange.Clear();
        }
    }
}